%% @doc テンプレートコンテキストとデリミタを管理する
%%
-module(templ_dict).
-export([init/1]).
-export([set_context/1, put_value/2, remove_value/1, get_context/0]).
-export([set_delim/2, get_ldelim/0, get_rdelim/0]).
-export([append_text/1, append_if/1, append_let/2, append_foreach/2, append_else/0, append_expr/1]).
-export([pop_stmt/0, pop_if_stmt/0, pop_let_stmt/0, pop_foreach_stmt/0]).
-export([get_stmt/0, reset_stmt/0]).

%% @type key() = string()
%% @type index() = int()
%% @type value() = string()
%% @type delim() = string()


%% @spec init(list()) -> ok
%% @doc Initiates the server
%%
%init([]) -> {ok, #state{}}.
init(List) -> 
	Dict = dict:from_list(List),
	%{ok, #state{ctx = Dict}}.
	put(context, Dict),
	put(ldelim, "{"),
	put(rdelim, "}"),
	put(stmt, []),
	ok.

%% @spec set_context(list()) -> any()
%% @doc コンテキストを設定する
%%
set_context(List) ->
	Ctx = dict:from_list(List),
	%NewState = State#state{ctx = Ctx},
	%{noreply, NewState}.
	put(context, Ctx).

%% @spec put_value(key(), value()) -> any()
%% @doc キーと値の組を追加する
%%
put_value(Key, Value) ->
	%Ctx = State#state.ctx,
	Ctx = get_context(),
	NewCtx = case dict:is_key(Key, Ctx) of
				  true  -> erlang:error({keyexists,Key});
				  false -> dict:store(Key, Value, Ctx)
			 end,
	%NewState = State#state{ctx = NewCtx},
	%{noreply, NewState}.
	put(context, NewCtx).

%% @spec remove_value(key()) -> any()
%% @doc キーの値を削除する
%%
remove_value(Key) ->
	%Ctx = State#state.ctx,
	Ctx = get_context(),
	NewCtx = dict:erase(Key, Ctx),
	%NewState = State#state{ctx = NewCtx},
	%{noreply, NewState}.
	put(context, NewCtx).

%% @spec get_context() -> context()
%% @doc コンテキストを得る
%%
get_context() ->
	%Ctx = State#state.ctx,
	Ctx = case get(context) of
			  undefined -> [];
			  C -> C
		  end,
	%{reply, Ctx, State}.
	Ctx.


%% @spec set_delim(delim(), delim()) -> any()
%% @doc デリミタを設定する
%%
set_delim(LDelim, RDelim) ->
	%State1 = State#state{ldelim = LDelim},
	%State2 = State1#state{rdelim = RDelim},
	%{noreply, State2}.
	put(ldelim, LDelim),
	put(rdelim, RDelim).

%% @spec get_ldelim() -> delim()
%% @doc 開始デリミタを得る
%%
get_ldelim() ->
	%LDelim = State#state.ldelim,
	%{reply, LDelim, State}.
	case get(ldelim) of
		undefined -> "{";
		LDelim -> LDelim
	end.

%% @spec get_rdelim() -> delim()
%% @doc 終了デリミタを得る
%%
get_rdelim() ->
	%RDelim = State#state.rdelim,
	%{reply, RDelim, State}.
	case get(rdelim) of
		undefined -> "}";
		RDelim -> RDelim
	end.


append_text(Text) when is_list(Text) ->
	append_stmt({ok,Text}).
append_expr({expr,_}=Expr) ->
	append_stmt(Expr).
append_stmt(Stmt) ->
	SL = get_stmt(),
	NewStmt = case SL of
		[]    -> [[Stmt]];
		[S|R] -> [S++[Stmt]|R]
	end,
	put(stmt, NewStmt).

append_if({expr,_}=Cond) ->
	append_and_push_stmt({if_,Cond}).
append_let({expr,_}=Name, {expr,_}=Value) ->
	append_and_push_stmt({let_, Name, Value}).
append_foreach({expr,_}=Name, {expr,_}=List) ->
	append_and_push_stmt({foreach, Name, List}).
append_and_push_stmt(Stmt) ->
	SL = get_stmt(),
	NewStmt = case SL of
		[]    -> [[],{Stmt,[]}];
		[S|R] -> [[],{Stmt,S}|R]
	end,
	put(stmt, NewStmt).

append_else() ->
	[_E1,{E2,_E3}|_R] = get_stmt(),
	pop_stmt(),
	case E2 of
		{if_,_}       -> append_and_push_stmt(elseif);
		{let_,_,_}    -> append_and_push_stmt(elselet);
		{foreach,_,_} -> append_and_push_stmt(elseforeach)
	end.

pop_stmt() ->
	[E1,{E2,E3}|R] = get_stmt(),
	NewExpr = [E3++[E2]++[E1]|R],
	put(stmt, NewExpr).
pop_if_stmt() ->
	[_E1,{E2,_E3}|_R] = get_stmt(),
	case E2 of
		{if_,_} -> pop_stmt();
		elseif  -> pop_stmt();
		_ -> erlang:error({wrongsyntax,E2})
	end.
pop_let_stmt() ->
	[_E1,{E2,_E3}|_R] = get_stmt(),
	case E2 of
		{let_,_,_} -> pop_stmt();
		elselet  -> pop_stmt();
		_ -> erlang:error({wrongsyntax,E2})
	end.
pop_foreach_stmt() ->
	[_E1,{E2,_E3}|_R] = get_stmt(),
	case E2 of
		{foreach,_,_} -> pop_stmt();
		elseforeach -> pop_stmt();
		_ -> erlang:error({wrongsyntax,E2})
	end.

get_stmt() ->
	case get(stmt) of
		undefined -> [];
		Stmt -> Stmt
	end.
reset_stmt() ->
	put(stmt, []).
